package com.liang.recommend.algorithm;

import com.liang.recommend.pojo.UserAction;

import java.util.List;

//皮尔逊相关系数
public class Pearson {

    /**
     * 测试启动类
     * @param args
     */
    public static void main(String[] args) {
                  forTest();
      }

    /**
     * 测试数据集
     */
    private static void forTest(){
        /*用于测试*/
//        double[] y = new double[] { 0.98, 0.96, 0.96, 0.94, 0.925, 0.9025, 0.875 };
//        double[] x = new double[] { 1, 1, 1, 1, 0.961483893, 0.490591662, 0.837341784 };
        double[] x = new double[] {5.8,2.6,5.72,2.6,5.92};
        double[] y = new double[] {5.68,2.4,5.76,2.4,5.52};
        double score = getPearsonCorrelationScore(x, y);
        System.out.println(score);//0.6350393282549671
    }

    /**
     * 得到皮尔森系数方式1
     * @param x
     * @param y
     * @return
     */
    public  double getPearsonCorrelationScore(List<UserAction> x, List<UserAction> y) {
        double distance=0;
        double countTemp;
        int temp=0;
        int size=0;
        for (UserAction userAction : x) {
            for (UserAction action : y) {
                if(userAction.getMovieId()==action.getMovieId()){
                    size+=1;
                    break;
                }
            }
        }
        if(size<0){
            System.out.println("两者没有评估过同一个电影");
            return 0;
        }
        double[] xData = new double[size];
        double[] yData = new double[size];
        for (int i = 0; i < x.size(); i++) {
            UserAction xAction = x.get(i);
            for (int j =0;j < y.size(); j++){
                UserAction yAction = y.get(j);
                if (yAction.getMovieId()==xAction.getMovieId()){
                    xData[temp]=xAction.getScore();
                    yData[temp]=yAction.getScore();
                    temp+=1;
                    break;//找到就跳出，不用遍历完
                }
            }
        }
        countTemp=getPearsonCorrelationScore(xData,yData);
        //处理NaN
        if(!Double.isNaN(countTemp)){
            distance=countTemp;
        }
        return distance;
    }

    /**
     * 得到皮尔森系数方式2
     * @param xData
     * @param yData
     * @return
     */
    public static double getPearsonCorrelationScore(double[] xData, double[] yData) {
        if (xData.length != yData.length)
            throw new RuntimeException("数据不正确！");
        double xMeans;
        double yMeans;
        double numerator = 0;// 求解皮尔逊的分子
        double denominator = 0;// 求解皮尔逊系数的分母

        double result = 0;
        // 拿到两个数据的平均值
        xMeans = getMeans(xData);
        yMeans = getMeans(yData);
        // 计算皮尔逊系数的分子
        numerator = generateNumerator(xData, xMeans, yData, yMeans);
        // 计算皮尔逊系数的分母
        denominator = generateDenomiator(xData, xMeans, yData, yMeans);
        // 计算皮尔逊系数
        result = numerator / denominator;
        return result;
    }

    /**
     * 计算分子
     *
     * @param xData
     * @param xMeans
     * @param yData
     * @param yMeans
     * @return
     */
    private static double generateNumerator(double[] xData, double xMeans, double[] yData, double yMeans) {
        double numerator = 0.0;
        for (int i = 0; i < xData.length; i++) {
            numerator += (xData[i] - xMeans) * (yData[i] - yMeans);
        }
        return numerator;
    }

    /**
     * 生成分母
     *
     * @param yMeans
     * @param yData
     * @param xMeans
     * @param xData
     * @return 分母
     */
    private static double generateDenomiator(double[] xData, double xMeans, double[] yData, double yMeans) {
        double xSum = 0.0;
        for (int i = 0; i < xData.length; i++) {
            xSum += (xData[i] - xMeans) * (xData[i] - xMeans);
        }
        double ySum = 0.0;
        for (int i = 0; i < yData.length; i++) {
            ySum += (yData[i] - yMeans) * (yData[i] - yMeans);
        }
        return Math.sqrt(xSum) * Math.sqrt(ySum);
    }

    /**
     * 根据给定的数据集进行平均值计算
     *
     * @param datas
     * @return 给定数据集的平均值
     */
    private static double getMeans(double[] datas) {
        double sum = 0.0;
        for (int i = 0; i < datas.length; i++) {
            sum += datas[i];
        }
        return sum / datas.length;
    }
}
